package com.hoioy.clazz.spellearn;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class HelloWorldEvaluationContext {
    public static void main(String[] args) {
        //1. 最简单的表达式
//        String str = "'Hello World'.concat('!')"; //定义表达式
//        ExpressionParser parser = new SpelExpressionParser();//定义转换器，可以Ctrl+H查看转换器类树
//        Expression expression = parser.parseExpression(str);//解析字符串语句生成Java对象结构描述的表达式，也就是JVM虚拟机能够执行的结构
//        System.out.println(expression.getValue());//计算结果


        //问题1.表达式除了写Hello Word字符串相关还能写什么呢？数字、等等
        //运行环境、上下文简单理解：语言之所以丰富，是因为这个环境中有数据和方法供我们使用，比如Java。
        // SpEL也有上下文的概念，假如没有上下文，那么 SPEL 的描述能力就有限，计算能力有限
//
//        one();
//
        two();
    }

    //rootObject
    public static void one() {
        //怎么指定上下文呢? 查看getValue方法, 有 rootObject 和 EvaluationContext
        ExpressionParser parser = new SpelExpressionParser();
        //思考，可以不使用new关键字直接使用对象吗？,之前可以直接new，如下：
        System.out.println(parser.parseExpression("new com.hoioy.clazz.spellearn.Foo('name').name").getValue());

        Foo foo = new Foo("foo");
        //直接设置为 rootObject
        System.out.println(parser.parseExpression("getName()").getValue(foo));
        System.out.println(parser.parseExpression("name").getValue(foo));

        //不传rootObject行吗？报错
//        System.out.println(parser.parseExpression("foo.getName()").getValue());
        //需要加foo前缀吗？报错
//         System.out.println(parser.parseExpression("foo.getName()").getValue(foo));

        //如果getValue()，不手动设置，那么 rootObject 默认就是null，TypedValue.NULL
        //我们可以debug试一下
    }

    //上下文环境
    public static void two() {
        Foo foo = new Foo("foo");
        ExpressionParser parser = new SpelExpressionParser();    // 定义一个Spring表达式解析器

        // 进行最终表达式的计算，还有一个 SimpleEvaluationContext 只包含部分功能
        // 我们讲解时候使用 StandardEvaluationContext

        //通过单个根对象，可以向表达式公开一个全面的自定义环境，例如自定义实用程序方法或变量。
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setRootObject(foo);
        Expression exp = parser.parseExpression("name");
        System.out.println(exp.getValue(context));

        //可以直接指定`根上下文对象`,都是context只是写法不同，不重要
        context = new StandardEvaluationContext(foo);

        //StandardEvaluationContext还有很多其他功能,更加丰富
        //在运行环境中设置自定义变量
        context.setVariable("v1", "你好啊");
        //直接使用报错
//         exp = parser.parseExpression("v1");
        //需要使用#号引用变量
        exp = parser.parseExpression("#v1");
        System.out.println(exp.getValue(context));

        //在运行环境中设置变量举例，这实际上是Spring Boot的@Value注解能拿到系统参数的原因
        context.setVariable("systemProperties", System.getProperties());
        System.out.println(parser.parseExpression("#systemProperties").getValue(context));
        System.out.println(parser.parseExpression("#systemProperties['sun.desktop']").getValue(context));


        // SimpleEvaluationContext 和 StandardEvaluationContext 区别

    }
}
